package com.alan.camunda.boot.listener;


import com.alan.camunda.boot.dto.MyTxEvent;
import com.alan.camunda.boot.util.BpmnUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.impl.history.event.HistoricProcessInstanceEventEntity;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.camunda.bpm.engine.impl.history.event.HistoryEventTypes;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.spring.boot.starter.event.ExecutionEvent;
import org.camunda.bpm.spring.boot.starter.event.TaskEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * https://docs.camunda.org/manual/latest/user-guide/spring-boot-integration/the-spring-event-bridge/
 *
 */
@Slf4j
@Component
public class GlobalListener {
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ApplicationEventPublisher publisher;

    /** 人员任务才会执行这个 */
    @EventListener
    public void onTaskEvent(DelegateTask taskDelegate) {
        log.info("GlobalListener onTaskEvent DelegateTask 节点名: {} eventName:{}", taskDelegate.getTaskDefinitionKey(), taskDelegate.getEventName());

        // handle mutable task event
        if ("assignment".equals(taskDelegate.getEventName())) {
            log.info("=============> Task {} 分配处理人  {}, taskID: {}",
                    taskDelegate.getName(), taskDelegate.getAssignee(), taskDelegate.getId());
        }

    }

    /** 人员任务才会执行这个 */
    @EventListener
    public void onTaskEvent(TaskEvent taskEvent) {
        log.info("GlobalListener onTaskEvent TaskEvent 节点名: {} eventName:{}", taskEvent.getTaskDefinitionKey(), taskEvent.getEventName());
        // handle immutable task event
    }


    @EventListener
    public void onExecutionEvent(DelegateExecution executionDelegate) {

        Object trace = executionDelegate.getVariable("_trace");
        if (trace == null) {
            Map<String, Long> map = new HashMap<>();
            map.put(executionDelegate.getCurrentActivityId(), System.currentTimeMillis());
            executionDelegate.setVariable("_trace", map);
        } else {
            Map<String, Long> m = (Map<String, Long>)trace;
            m.put(executionDelegate.getCurrentActivityId(), System.currentTimeMillis());
            executionDelegate.setVariable("_trace", m);
        }

        log.info("GlobalListener onExecutionEvent DelegateExecution 节点名: {} eventName:{}", executionDelegate.getCurrentActivityId(), executionDelegate.getEventName());
        // handle mutable execution event
    }

    @EventListener
    public void onExecutionEvent(ExecutionEvent executionEvent) {
        log.info("GlobalListener onExecutionEvent ExecutionEvent 节点名: {} eventName:{}", executionEvent.getCurrentActivityId(), executionEvent.getEventName());
        // handle immutable execution event
    }

    @EventListener
    public void onHistoryEvent(HistoryEvent historyEvent) {
        publisher.publishEvent(new MyTxEvent());

        log.info("GlobalListener onHistoryEvent HistoryEvent Event Type:{} HistoryEventClass: {}", historyEvent.getEventType(), historyEvent.getClass());
        if (historyEvent instanceof HistoricProcessInstanceEventEntity hpi) {
            if (HistoricProcessInstance.STATE_COMPLETED.equals(hpi.getState())
                    && HistoryEventTypes.PROCESS_INSTANCE_END.getEventName().equals(hpi.getEventType())) {
               if (StringUtils.isNotBlank(hpi.getEndActivityId())) {
                   BpmnModelInstance bmi = repositoryService.getBpmnModelInstance(hpi.getProcessDefinitionId());
                   if (BpmnUtil.isTopLevelTerminateEndNode(bmi, hpi.getEndActivityId())) {
                          log.info("Process instance {} is terminated", hpi.getProcessInstanceId());
                   }
               }
            }
        }
        // handle history event
    }

}
